/*
 * @(#)JdbcFactWriter.java 1.0 2000/12/14
 * 
 * Copyright 2000 Thomas Barnekow. All Rights Reserved.
 * 
 * This software is the proprietary information of Thomas Barnekow. Use is
 * subject to license terms.
 */

package jessx.provider.jdbc;

import java.sql.*;

import jess.*;
import jessx.provider.*;

import tb.jots.*;
import tb.util.*;

/**
 * A JDBC {@link FactWriter}.
 * 
 * @author Thomas Barnekow
 * @version 1.0
 */
public class JdbcFactWriter extends JdbcFactReader implements FactWriter {

	public JdbcFactWriter(QualifiedName providerName, Connection connection) {
		super(providerName, connection);
	}

	public JdbcFactWriter(
		QualifiedName providerName,
		String url,
		String userName,
		String password) {
		super(providerName, url, userName, password);
	}

	/**
	 * Return the current transaction context, i.e., the {@link Control}object
	 * reference, if a transaction has been begun (see {@link Current#begin}.)
	 * Otherwise, delegate to the superclass' method.
	 */
	protected Object getUnsharedConnectionContext() {
		Control control = OTS.getCurrent().getControl();
		if (control != null)
			return control;
		else
			return super.getUnsharedConnectionContext();
	}

	/*
	 * Provider operations
	 */

	public void provide(QualifiedName service, QualifiedName entityName) {
		getProviderSupport().provide(service, entityName);
	}

	/*
	 * FactWriter operations
	 */

	/**
	 * Assert (insert) database tuple corresponding to the given <i>fact</i>.
	 * 
	 * @param entityName
	 *            table name
	 * @param fact
	 *            Jess fact used to define the query's WHERE clause
	 * @param context
	 *            Jess context
	 */
	public Fact assertFact(
		QualifiedName entityName,
		Fact fact,
		Context context)
		throws JessException {
		StringBuffer query = new StringBuffer(256);
		StringBuffer names = new StringBuffer(128);
		StringBuffer values = new StringBuffer(128);

		query.append("INSERT INTO ").append(entityName.toString("."));

		Deftemplate dt = fact.getDeftemplate();
		int nslots = dt.getNSlots();

		int index;
		String slotName = null;
		Value slotValue = null;

		// Find first non-nil slot value
		for (index = 0; index < nslots; index++) {
			slotName = dt.getSlotName(index);
			slotValue = fact.getSlotValue(slotName);
			if (!slotValue.equals(Funcall.NIL)) {
				names.append(slotName);
				values.append(
					getValue(slotValue, dt.getSlotType(index), context));
				break;
			}
		}

		if (index >= nslots)
			return null;

		// Append next names/values
		for (++index; index < nslots; index++) {
			slotName = dt.getSlotName(index);
			slotValue = fact.getSlotValue(slotName);
			if (!slotValue.equals(Funcall.NIL)) {
				names.append(',').append(slotName);
				values.append(',').append(
					getValue(slotValue, dt.getSlotDataType(index), context));
			}
		}

		query.append(" (").append(names).append(") values (").append(
			values).append(
			')');

		try {
			executeUpdate(query.toString());
		} catch (Exception ex) {
			System.out.println(ex);
			throw new JessException(
				"JdbcFactWriter.assert",
				"Exception caught",
				ex);
		}

		return fact;
	}

	/**
	 * Retract (delete) database tuple corresponding to the given <i>fact</i>.
	 * 
	 * @param entityName
	 *            table name
	 * @param fact
	 *            Jess fact used to define the query's WHERE clause
	 * @param context
	 *            Jess context
	 */
	public Fact retract(QualifiedName entityName, Fact fact, Context context)
		throws JessException {
		StringBuffer query = new StringBuffer(256);
		query.append("DELETE FROM ").append(entityName.toString("."));

		Deftemplate dt = fact.getDeftemplate();
		int nslots = dt.getNSlots();

		int index;
		String slotName = null;
		Value slotValue = null;

		// Find first non-nil slot value
		for (index = 0; index < nslots; index++) {
			slotName = dt.getSlotName(index);
			slotValue = fact.getSlotValue(slotName);
			if (!slotValue.equals(Funcall.NIL)) {
				appendCondition(
					query.append(" WHERE "),
					slotName,
					dt.getSlotDataType(index),
					slotValue,
					context);
				break;
			}
		}

		// Append next conditions
		for (++index; index < nslots; index++) {
			slotName = dt.getSlotName(index);
			slotValue = fact.getSlotValue(slotName);
			if (!slotValue.equals(Funcall.NIL)) {
				appendCondition(
					query.append(" AND "),
					slotName,
					dt.getSlotDataType(index),
					slotValue,
					context);
			}
		}

		try {
			executeUpdate(query.toString());
		} catch (Exception ex) {
			throw new JessException(
				"JdbcFactWriter.retract",
				"Exception caught",
				ex);
		}

		return fact;
	}

	/*
	 * Helpers
	 */

	protected String getValue(Value value, int datatype, Context context)
		throws JessException {
		switch (datatype) {
			case RU.STRING :
				return "'" + value.stringValue(context) + "'";
			default :
				return value.stringValue(context);
		}
	}
}